extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/opt.h>
}
#include "xencode.h"
#include <fstream>
#include <iostream>
#ifdef main
#undef main
#endif // !main
using namespace std;

int main(int argc, char *argv[]) {
  string filename = "400_300_25";
  AVCodecID codec_id = AV_CODEC_ID_H264;
  if (argc > 1) {
    string codec = argv[1];
    if (codec == "h265" || codec == "hevc") {
      codec_id = AV_CODEC_ID_H265;
    } else {
    }
  }
  if (codec_id == AV_CODEC_ID_H264) {
    filename += ".h264";
  } else if (codec_id == AV_CODEC_ID_H265) {
    filename += ".h265";
  }
  // 输出文件
  ofstream ofs;
  ofs.open(filename, ios::binary);
  // 设置自定义日志回调函数
  av_log_set_level(AV_LOG_DEBUG);
  XEncode en;
  AVCodecContext *c = en.Create(codec_id);
  AVFrame *frame = nullptr;
  AVPacket *pkt = nullptr;
  // 1 查找编码器
  // 2 创建编码器上下文
  if (!c) {
    av_log(nullptr, AV_LOG_ERROR, "Cannot alloc codec context\n");
    return -1;
  }
  // 3 设置编码参数
  c->width = 400;
  c->height = 300;
  c->max_b_frames = 0;
  en.set_c(c);
  en.SepOpt("crf", 18);
  en.Open();
  //   c->gop_size = 6; //
  int count = 0;
  frame = en.CreateFrame();
  frame->linesize[0] = c->width;
  frame->linesize[1] = c->width / 2;
  frame->linesize[2] = c->width / 2;

  for (int i = 0; i < 500; ++i) {
    // 生成AVFrame数据
    // Y
    for (int y = 0; y < c->height; y++) {
      for (int x = 0; x < c->width; x++) {
        frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
      }
    }
    for (int y = 0; y < c->height / 2; y++) {
      for (int x = 0; x < c->width / 2; x++) {
        frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 3;
        frame->data[2][y * frame->linesize[2] + x] = 64 + y + i * 5;
      }
    }
    frame->pts = i;
    auto pkt = en.Encode(frame);
    if (pkt) {
      count++;
      ofs.write((char *)pkt->data, pkt->size);
      av_packet_free(&pkt);
    }
  }
  auto pkts = en.End();
  for (AVPacket *pkt : pkts) {
    count++;
    ofs.write((char *)pkt->data, pkt->size);
    av_packet_free(&pkt);
  }
  av_log(nullptr, AV_LOG_DEBUG, "encode :%d\n", count);
err:
  if (c)
    en.set_c(c);
  if (frame)
    av_frame_free(&frame);
  if (pkt)
    av_packet_free(&pkt);
  if (ofs.is_open()) {
    ofs.close();
  }
  return 0;
}
